//
// Copyright (c) 2007-2009 Stuart Morgan.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#import "CookieController.h"

#import "CaminoCookieStore.h"
#import "SafariCookieStore.h"

static NSString* kCaminoProcessName = @"Camino";

@interface CookieController (Private)
// Returns YES if Camino is currently running.
- (BOOL)isCaminoRunning;

// Adds |cookies| to |store|, updating the UI as necessary.
- (void)addCookies:(NSArray*)cookies toStore:(CookieStore*)store;

// Displays an error dialog with the given message and title.
// If |fatal| is true, the application will exit when the dialog is dismissed.
- (void)showErrorMessage:(NSString*)error
               withTitle:(NSString*)title
                 isFatal:(BOOL)fatal;

@end

@implementation CookieController

- (void)awakeFromNib {
  [self willChangeValueForKey:@"mCaminoCookieStore"];
  mCaminoCookieStore = [[CaminoCookieStore alloc] init];
  [self didChangeValueForKey:@"mCaminoCookieStore"];
  [mCaminoCookieStore loadCookies];
  [self willChangeValueForKey:@"mSafariCookieStore"];
  mSafariCookieStore = [[SafariCookieStore alloc] init];
  [self didChangeValueForKey:@"mSafariCookieStore"];
  [mSafariCookieStore loadCookies];

  [mWindow center];
}

- (void)dealloc {
  [mCaminoCookieStore release];
  [mSafariCookieStore release];
  [mSafeQuitDate release];
  [super dealloc];
}

- (IBAction)addCookiesToCamino:(id)sender {
  [self addCookies:[mSafariCookieStore cookies] toStore:mCaminoCookieStore];
}

- (IBAction)addCookiesToSafari:(id)sender {
  [self addCookies:[mCaminoCookieStore cookies] toStore:mSafariCookieStore];

  // NSHTTPCookieStore is buggy--changes don't actually persist if you quit
  // immediately after changing it (Safari has this problem too)--so keep track
  // of how long it's been since setting cookies so that we can delay quit if
  // necessary.
  mSafeQuitDate = [[NSDate dateWithTimeIntervalSinceNow:6] retain];
}

- (IBAction)syncCookies:(id)sender {
  [self addCookiesToCamino:nil];
  [self addCookiesToSafari:nil];
}

#pragma mark -

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
  if ([self isCaminoRunning]) {
    [self showErrorMessage:NSLocalizedString(@"CaminoRunningTitle", nil)
                 withTitle:NSLocalizedString(@"CaminoRunningText", nil)
                   isFatal:YES];
    return;
  }
  else if (!([mCaminoCookieStore cookies] && [mSafariCookieStore cookies])) {
    NSError* error = [mCaminoCookieStore cookies] ? [mSafariCookieStore lastError]
                                                  : [mCaminoCookieStore lastError];
    [self showErrorMessage:[error localizedFailureReason]
                 withTitle:[error localizedDescription]
                   isFatal:YES];
    return;
  }
}

- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication {
  return YES;
}

- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
  // TODO: Put up a progress sheet, rather than just silently sleeping.
  if (mSafeQuitDate &&
      ([(NSDate*)[NSDate date] compare:mSafeQuitDate] == NSOrderedAscending)) {
    [NSThread sleepUntilDate:mSafeQuitDate];
  }
  return NSTerminateNow;
}

#pragma mark -

- (void)showErrorMessage:(NSString*)error
               withTitle:(NSString*)title
                 isFatal:(BOOL)fatal {
  NSAlert* errorAlert = [[[NSAlert alloc] init] autorelease];
  [errorAlert setMessageText:title];
  [errorAlert setInformativeText:error];
  if (fatal)
    [errorAlert addButtonWithTitle:NSLocalizedString(@"Quit", nil)];
  [errorAlert beginSheetModalForWindow:mWindow
                         modalDelegate:self
                        didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
                           contextInfo:(void*)(fatal ? 1 : 0)];
}

- (void)alertDidEnd:(NSAlert*)alert
         returnCode:(int)returnCode
        contextInfo:(void*)contextInfo {
  if (contextInfo)  // A non-zero value here indicates a fatal error.
    [[NSApplication sharedApplication] terminate:self];
}

- (BOOL)isCaminoRunning {
  ProcessSerialNumber psn = {0, kNoProcess};
  while (GetNextProcess(&psn) == noErr) {
    NSString* processName;
    CopyProcessName(&psn, (CFStringRef*)&processName);
    BOOL foundCamino = [processName isEqualToString:kCaminoProcessName];
    [processName release];
    if (foundCamino)
      return YES;
  }
  return NO;
}

- (void)addCookies:(NSArray*)cookies toStore:(CookieStore*)store {
  if (![store addCookies:cookies]) {
    NSError* error = [store lastError];
    [self showErrorMessage:[error localizedFailureReason]
                 withTitle:[error localizedDescription]
                   isFatal:NO];
  }
}

@end
